Skip to content

[net11.0][Android] Implement handler based Shell architecture replacing legacy renderers#34758

Draft
Tamilarasan-Paranthaman wants to merge 26 commits intonet11.0from
Net11.0-Android-Shell-Handler
Draft

[net11.0][Android] Implement handler based Shell architecture replacing legacy renderers#34758
Tamilarasan-Paranthaman wants to merge 26 commits intonet11.0from
Net11.0-Android-Shell-Handler

Conversation

@Tamilarasan-Paranthaman
Copy link
Copy Markdown
Member

Note

Are you waiting for the changes in this PR to be merged?
It would be very helpful if you could test the resulting artifacts from this PR and let us know in a comment if this change resolves your issue. Thank you!

Description

  • This PR introduces handler-based Shell architecture for Android, replacing the legacy renderer-based approach (ShellRenderer, ShellFlyoutRenderer, ShellItemRenderer, ShellSectionRenderer) with new handler classes that reuse standard MAUI platform components. The new architecture follows the same patterns used by FlyoutViewHandler, NavigationViewHandler, and TabbedPageManager, achieving the long-standing architectural goal of building Shell from the same building blocks as non-Shell features.

Platform: Android only. iOS/MacCatalyst continue to use legacy ShellRenderer.

Motivation

The legacy Shell renderers on Android are monolithic, tightly coupled, and duplicate functionality that already exists in standard MAUI handlers:

  • ShellFlyoutRenderer extends DrawerLayout directly (IS-A relationship) — duplicates FlyoutViewHandler drawer logic
  • ShellItemRenderer manages its own BottomNavigationView — duplicates TabbedPageManager tab logic
  • ShellSectionRenderer manages its own toolbar, navigation stack, and content tabs — duplicates NavigationViewHandler and TabbedPageManager patterns
  • Fragment management, layout inflation, and view hierarchy are all custom per-renderer

The new handler architecture:

  • Reuses MauiDrawerLayout — same shared component as FlyoutViewHandler
  • Reuses TabbedViewManager — shared tab management for both Shell and TabbedPage
  • Uses XML layout inflation — follows established MAUI patterns (navigationlayout.axml, shellitemlayout.axml, shellsectionlayout.axml)
  • Maps cleanly to Shell's virtual view hierarchyShell → ShellHandler, ShellItem → ShellItemHandler, ShellSection → ShellSectionHandler

Architecture Overview

Handler Hierarchy

Shell (IFlyoutView)
└── ShellHandler : ViewHandler<Shell, MauiDrawerLayout>
    ├── MauiDrawerLayout (shared with FlyoutViewHandler)
    │   ├── navigationlayout.axml (content root)
    │   └── Flyout content (ShellFlyoutTemplatedContentRenderer — reused from legacy)
    │
    └── ShellItem
        └── ShellItemHandler : ElementHandler<ShellItem, ViewPager2>
            ├── shellitemlayout.axml (CoordinatorLayout + ViewPager2)
            ├── BottomNavigationView (via TabbedViewManager)
            ├── Toolbar (shared across all sections — persists on section switch)
            └── ShellSection
                └── ShellSectionHandler : ElementHandler<ShellSection, AView>
                    ├── shellsectionlayout.axml (LinearLayout + ViewPager2)
                    ├── TabLayout (via TabbedViewManager, hidden if single content)
                    └── ShellContent → StackNavigationManager (independent nav stack per content)

Key Design Decisions

Decision Rationale
Toolbar at ShellItem level Persists across section switches — no flicker, no recreate. Sections update toolbar content, not recreate it.
LinearLayout for ShellSection (not CoordinatorLayout) CoordinatorLayout caused a white-gap bug when TabLayout was hidden (empty AppBarLayout + ScrollingViewBehavior). LinearLayout correctly reclaims space with layout_weight.
XML layout inflation Follows NavigationViewHandler/FlyoutViewHandler patterns. Resolves ?attr/ theme tokens at inflation time. Developers can override via Android resource overlays.
OffscreenPageLimit = total items Prevents FragmentStateAdapter save/restore which causes crashes (fragments lose MAUI state). Same approach as TabbedPageRenderer.
Adapter pattern for legacy interfaces ShellItemHandlerAdapter and ShellSectionHandlerAdapter implement IShellItemRenderer/IShellSectionRenderer, maintaining compatibility with ShellToolbarTracker and appearance trackers.
ITabbedViewSource interface Lightweight alternative to ITabbedView (which extends IView). Lets Shell adapters provide tab data to TabbedViewManager without 40+ IView stub members.

New Files

Core Layer (src/Core/)

File Purpose
Platform/Android/MauiDrawerLayout.cs Shared DrawerLayout wrapper for FlyoutViewHandler and ShellHandler. Supports three layout modes: Flyout, SideBySide, Padding. Implements flyout width calculation per Material Design guidelines.
Platform/Android/Resources/Layout/shellitemlayout.axml XML layout for ShellItemHandlerCoordinatorLayout + ViewPager2. Toolbar, tabs, and BottomNavigationView placed into NRM slots.
Platform/Android/Resources/Layout/shellsectionlayout.axml XML layout for ShellSectionHandlerLinearLayout + ViewPager2.
Core/ITab.cs ITab interface — Title, Icon, IsEnabled for tab items in ITabbedView/ITabbedViewSource.
Primitives/TabBarPlacement.cs TabBarPlacement enum — Top / Bottom.

Controls Layer (src/Controls/)

File Purpose
Handlers/Shell/ShellHandler.Android.cs Main Shell handler. Uses MauiDrawerLayout with navigationlayout.axml. Manages flyout content, scrim brushes (including gradient via ScrimBrushDrawable), flyout behavior modes. Implements IShellContext to create handler-based renderers.
Handlers/Shell/ShellItemHandler.Android.cs ShellItem handler. Manages bottom navigation via TabbedViewManager, shared toolbar (persists across section switches), ViewPager2 for section fragments, appearance tracking.
Handlers/Shell/ShellSectionHandler.Android.cs ShellSection handler. Uses ViewPager2 for content switching (unified — works for single and multiple ShellContent). TabLayout visibility controlled by item count. Each ShellContent gets its own StackNavigationManager for independent navigation.
Handlers/Shell/ShellTabbedViewAdapters.Android.cs Adapter classes: ShellItemTabbedViewAdapter (bottom tabs), ShellSectionTabbedViewAdapter (top tabs), ShellSectionTab, ShellContentTab. Bridge Shell data model to ITabbedViewSource for TabbedViewManager.
Platform/Android/ITabbedViewSource.cs Lightweight interface for TabbedViewManager consumers. Same shape as ITabbedView but doesn't extend IView.
Platform/Android/TabbedViewManager.cs Shared tab management — handles ViewPager2, BottomNavigationView, TabLayout, fragment placement, tab appearance. Used by TabbedPageManager, ShellItemHandler, and ShellSectionHandler.

Modified Files

Handler Registration

File Change
Hosting/AppHostBuilderExtensions.cs Android Shell registration now conditionally registers handlers when UseAndroidShellHandlers=true, legacy ShellRenderer otherwise.
Handlers/Shell/ShellHandler.cs Added Shell property mapper entries — routes property changes to platform-specific handler methods.

Opt-In Infrastructure

File Change
Core/RuntimeFeature.cs Added UseAndroidShellHandlers feature switch (default: false). Follows the same pattern as UseMaterial3.
Build.Tasks/.../Microsoft.Maui.Controls.targets Maps UseAndroidShellHandlers MSBuild property to the runtime feature switch.

Shared Component Extraction

File Change
Handlers/FlyoutView/FlyoutViewHandler.Android.cs Refactored to use MauiDrawerLayout instead of inline DrawerLayout logic. Drawer functionality extracted to shared MauiDrawerLayout.
Platform/Android/TabbedPageManager.cs Refactored to use TabbedViewManager for tab management. Reduced from ~984 lines of duplicated logic to delegating to the shared manager.
Platform/Android/Navigation/StackNavigationManager.cs Minor changes for Shell integration — supports Shell's per-content navigation stacks.

Core Interfaces

File Change
Core/ITabbedView.cs Expanded with full tab management properties: Tabs, CurrentTab, BarBackgroundColor, BarBackground, BarTextColor, UnselectedTabColor, SelectedTabColor, TabBarPlacement, OffscreenPageLimit, IsSwipePagingEnabled, IsSmoothScrollEnabled, TabsChanged event.

Compatibility Layer Fixes

File Change
ShellFlyoutTemplatedContentRenderer.cs Updated to work with both renderer and handler paths. The handler's IShellContext provides handler-based adapters while keeping the same flyout content rendering.
ShellFlyoutRecyclerAdapter.cs Minor fix for handler compatibility.
ShellSearchViewAdapter.cs Added JNI constructor on CustomFilter inner class — required for Android runtime to instantiate via reflection.
ShellToolbarTracker.cs Updated to work with handler-provided toolbar. Shared between renderer and handler paths.
ShellToolbarAppearanceTracker.cs Minor update for handler compatibility.

Virtual View Changes

File Change
Element/Element.cs Changes to support handler-based Shell element hierarchy.
Shell/ShellContent.cs Added support for handler-based Shell content management.
TabbedPage/TabbedPage.cs Updated to implement expanded ITabbedView interface members.
Style.cs Minor cleanup.

PublicAPI

Updated PublicAPI.Unshipped.txt files across all TFMs for new public types and interface members:

  • MauiDrawerLayout, MauiDrawerLayout.FlyoutLayoutMode
  • ITab, ITabbedView expanded members
  • TabBarPlacement enum
  • ShellHandler, ShellItemHandler, ShellSectionHandler handler types

Shared Infrastructure Summary

The PR achieves the core architectural goal — Shell now uses the same building blocks as non-Shell features:

Component Used By Shell Also Used By
MauiDrawerLayout ShellHandler (flyout drawer) FlyoutViewHandler (FlyoutPage)
TabbedViewManager ShellItemHandler (bottom tabs), ShellSectionHandler (top tabs) TabbedPageManager (TabbedPage)
StackNavigationManager ShellSectionHandler (per-content nav stack) NavigationViewHandler (NavigationPage)
navigationlayout.axml ShellHandler (content root) FlyoutViewHandler, NavigationViewHandler
ITab / ITabbedView Shell adapters TabbedPage

Fragment Architecture

Shell handlers use wrapper fragments to integrate with Android's FragmentManager:

FragmentManager (Activity)
└── ShellItemWrapperFragment (committed by ShellHandler)
    ├── Inflates shellitemlayout.axml
    ├── Sets up ShellItemHandler with real ViewPager2 from XML
    │
    └── ChildFragmentManager
        └── ShellSectionWrapperFragment (via ViewPager2 FragmentStateAdapter)
            ├── Inflates shellsectionlayout.axml
            ├── Sets up ShellSectionHandler with real ViewPager2 from XML
            │
            └── ChildFragmentManager
                └── ShellContentNavigationFragment (via ViewPager2 FragmentStateAdapter)
                    ├── Uses StackNavigationManager for navigation
                    └── Hosts actual page content

All fragment subclasses have default constructors for Android's Fragment.instantiate() reflection requirement, with null guards in OnCreateView() for graceful restoration handling.

Opt-In Mechanism

The Shell on Android now supports both the legacy renderer-based approach and the new handler-based approach, controlled by the UseAndroidShellHandlers MSBuild property (following the same pattern as UseMaterial3).

How to Enable

<!-- In .csproj or Directory.Build.props -->
<PropertyGroup>
  <UseAndroidShellHandlers>true</UseAndroidShellHandlers>
</PropertyGroup>

Or via command line: dotnet build -p:UseAndroidShellHandlers=true

Flow

UseAndroidShellHandlers MSBuild property → build targets → AppHostBuilderExtensions conditionally registers handlers or legacy ShellRenderer.

What Changes When Enabled

Component Legacy (default) Handler (UseAndroidShellHandlers=true)
Shell ShellRenderer ShellHandlerMauiDrawerLayout
ShellItem Managed by ShellItemRenderer ShellItemHandlerViewPager2 + TabbedViewManager
ShellSection Managed by ShellSectionRenderer ShellSectionHandlerViewPager2 + StackNavigationManager

Note: iOS/MacCatalyst are not affected — they always use ShellRenderer regardless of this setting.

Testing

  • UseAndroidShellHandlers=true is set in the following test/sample projects for CI validation:
    • Controls.TestCases.HostApp.csproj — UI tests
    • Controls.DeviceTests.csproj — Device tests
  • No new device tests required — the handler produces identical visual output to the renderer
  • Handler is enabled in this branch to validate against the full UI test suite

Issues Fixed

Fixes #32985

Copilot AI review requested due to automatic review settings March 31, 2026 14:23
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Mar 31, 2026

🚀 Dogfood this PR with:

⚠️ WARNING: Do not do this without first carefully reviewing the code of this PR to satisfy yourself it is safe.

curl -fsSL https://raw.githubusercontent.com/dotnet/maui/main/eng/scripts/get-maui-pr.sh | bash -s -- 34758

Or

  • Run remotely in PowerShell:
iex "& { $(irm https://raw.githubusercontent.com/dotnet/maui/main/eng/scripts/get-maui-pr.ps1) } 34758"

@Tamilarasan-Paranthaman Tamilarasan-Paranthaman added the area-controls-shell Shell Navigation, Routes, Tabs, Flyout label Mar 31, 2026
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Implements a new handler-based Shell architecture for Android (opt-in via UseAndroidShellHandlers) and refactors shared Android navigation/tab/flyout infrastructure to reduce duplication with existing MAUI handlers/managers.

Changes:

  • Added RuntimeFeature.UseAndroidShellHandlers (default false) and MSBuild plumbing to enable the feature switch.
  • Introduced shared Android components/layouts (e.g., MauiDrawerLayout, TabbedViewManager, shellitemlayout.axml, shellsectionlayout.axml) and refactored FlyoutViewHandler/TabbedPageManager to use them.
  • Updated Shell compatibility components and test projects to validate the new Android Shell handlers in CI (plus a UI test stabilization tweak).

Reviewed changes

Copilot reviewed 40 out of 40 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
src/Core/src/RuntimeFeature.cs Adds UseAndroidShellHandlers runtime feature switch.
src/Core/src/PublicAPI/netstandard2.0/PublicAPI.Unshipped.txt Public API updates for new tab abstractions/enums.
src/Core/src/PublicAPI/netstandard/PublicAPI.Unshipped.txt Public API updates for new tab abstractions/enums.
src/Core/src/PublicAPI/net/PublicAPI.Unshipped.txt Public API updates for new tab abstractions/enums.
src/Core/src/PublicAPI/net-windows/PublicAPI.Unshipped.txt Public API updates for new tab abstractions/enums.
src/Core/src/PublicAPI/net-tizen/PublicAPI.Unshipped.txt Public API updates for new tab abstractions/enums.
src/Core/src/PublicAPI/net-maccatalyst/PublicAPI.Unshipped.txt Public API updates for new tab abstractions/enums.
src/Core/src/PublicAPI/net-ios/PublicAPI.Unshipped.txt Public API updates for new tab abstractions/enums.
src/Core/src/PublicAPI/net-android/PublicAPI.Unshipped.txt Public API updates including MauiDrawerLayout and handler signature changes.
src/Core/src/Primitives/TabBarPlacement.cs Introduces TabBarPlacement enum.
src/Core/src/Platform/Android/Resources/values/styles.xml Adds Android style for Shell TabLayout.
src/Core/src/Platform/Android/Resources/Layout/shellsectionlayout.axml New Android layout used by ShellSection handler.
src/Core/src/Platform/Android/Resources/Layout/shellitemlayout.axml New Android layout used by ShellItem handler.
src/Core/src/Platform/Android/Navigation/StackNavigationManager.cs Adds navigation request queueing and Shell integration for per-tab containers.
src/Core/src/Platform/Android/MauiDrawerLayout.cs New shared DrawerLayout wrapper used by FlyoutView/Shell.
src/Core/src/Handlers/FlyoutView/FlyoutViewHandler.Android.cs Refactors FlyoutViewHandler to use MauiDrawerLayout.
src/Core/src/Core/ITabbedView.cs Expands ITabbedView to support shared tab management surface.
src/Core/src/Core/ITab.cs Adds ITab abstraction for tab items.
src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/XFIssue/ShellSearchHandlerItemSizing.cs Stabilizes screenshot capture via retry/tolerance.
src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj Enables UseAndroidShellHandlers for UI test host app.
src/Controls/tests/DeviceTests/Controls.DeviceTests.csproj Enables UseAndroidShellHandlers for device tests.
src/Controls/src/Core/TabbedPage/TabbedPage.cs Implements expanded ITabbedView surface on TabbedPage.
src/Controls/src/Core/Shell/ShellContent.cs Propagates title updates to support handler-based tab title refresh.
src/Controls/src/Core/PublicAPI/net-android/PublicAPI.Unshipped.txt Adds public handler types/methods for Android Shell handlers.
src/Controls/src/Core/Platform/Android/TabbedViewManager.cs New shared manager for ViewPager2 + BottomNavigationView/TabLayout behavior.
src/Controls/src/Core/Platform/Android/TabbedPageManager.cs Refactors TabbedPageManager to delegate tab UI logic to TabbedViewManager.
src/Controls/src/Core/Platform/Android/ITabbedViewSource.cs Adds internal adapter interface to supply tab data without IView.
src/Controls/src/Core/Hosting/AppHostBuilderExtensions.cs Conditionally registers Android Shell handlers based on runtime feature.
src/Controls/src/Core/Handlers/Shell/ShellTabbedViewAdapters.Android.cs Adds Shell adapters bridging ShellItem/ShellSection to tab source model.
src/Controls/src/Core/Handlers/Shell/ShellHandler.Tizen.cs Adds stub mappers to satisfy shared mapper entries.
src/Controls/src/Core/Handlers/Shell/ShellHandler.cs Extends property mapper for Android/Tizen/Windows handler scenarios.
src/Controls/src/Core/Handlers/Shell/ShellHandler.Android.cs New Android ShellHandler implementation built on MauiDrawerLayout.
src/Controls/src/Core/Compatibility/Handlers/Shell/Android/ShellToolbarTracker.cs Compatibility updates for toolbar/search behavior and back icon progress handling.
src/Controls/src/Core/Compatibility/Handlers/Shell/Android/ShellToolbarAppearanceTracker.cs Adds null-guard in SetAppearance.
src/Controls/src/Core/Compatibility/Handlers/Shell/Android/ShellSearchViewAdapter.cs Adds JNI ctor + null guard for filter publish.
src/Controls/src/Core/Compatibility/Handlers/Shell/Android/ShellFlyoutTemplatedContentRenderer.cs Avoids double-updates when running under new handler path; exposes update methods.
src/Controls/src/Core/Compatibility/Handlers/Shell/Android/ShellFlyoutRecyclerAdapter.cs Adds additional null/dispose safety.
src/Controls/src/Build.Tasks/nuget/buildTransitive/netstandard2.0/Microsoft.Maui.Controls.targets Maps MSBuild property to runtime feature switch.

@Tamilarasan-Paranthaman Tamilarasan-Paranthaman force-pushed the Net11.0-Android-Shell-Handler branch from 9661c82 to 3e7bde8 Compare April 1, 2026 07:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area-controls-shell Shell Navigation, Routes, Tabs, Flyout community ✨ Community Contribution partner/syncfusion Issues / PR's with Syncfusion collaboration platform/android

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants